package models

import helpers._
import mongodb._
import org.mongodb.scala._
import org.mongodb.scala.bson.BsonObjectId
import play.api.libs.functional.syntax._
import play.api.libs.json._

import scala.concurrent._

case class GzhInfo(
    _id: BsonObjectId = BsonObjectId(),
    name: String,
    gzhid: String,
    appid: String,
    secret: String,
    token: String,
    qunku: String,
    channelId: String,
    isAlive: Boolean,
    h5: Option[GzhInfo.H5],
    createTime: Long,
    updateTime: Long
) extends HasBsonObjectID

object GzhInfo extends GzhInfoCNamed with ExceptionDefining {

  case class NotFound(appid: String) extends PandoraMongodb.NotFound(errorCode(appid))

  case class H5(qrCode: String, description: String)

  object H5 {

    implicit val jsonFormat: Format[H5] = Json.format[H5]
  }

  implicit val jsonFormat: Format[GzhInfo] = Format[GzhInfo](
    /**/ Translated
      .readObjectId("_id")
      .and /**/ ((__ \ "name").read[String])
      .and /**/ ((__ \ "gzhid").read[String])
      .and /**/ ((__ \ "appid").read[String])
      .and /**/ ((__ \ "secret").read[String])
      .and /**/ ((__ \ "token").read[String])
      .and /**/ ((__ \ "qunku").read[String])
      .and /**/ ((__ \ "channelId").read[String])
      .and /**/ ((__ \ "isAlive").read[Boolean])
      .and /**/ ((__ \ "h5").readNullable[H5])
      .and /**/ ((__ \ "createTime").read[Long])
      .and /**/ ((__ \ "updateTime").read[Long])(
      GzhInfo.apply _
    ),
    Writes[GzhInfo] { obj ⇒
      /**/
      Translated
        .writeObjectId("_id")
        .and /**/ ((__ \ "name").write[String])
        .and /**/ ((__ \ "gzhid").write[String])
        .and /**/ ((__ \ "appid").write[String])
        .and /**/ ((__ \ "secret").write[String])
        .and /**/ ((__ \ "token").write[String])
        .and /**/ ((__ \ "qunku").write[String])
        .and /**/ ((__ \ "channelId").write[String])
        .and /**/ ((__ \ "isAlive").write[Boolean])
        .and /**/ ((__ \ "h5").writeNullable[H5])
        .and /**/ ((__ \ "createTime").write[Long])
        .and /**/ ((__ \ "updateTime").write[Long])(
          unlift(GzhInfo.unapply)
        )
        .writes(obj)
    }
  )
}

trait GzhInfoCollection extends ExtendMongodbQL[GzhInfo] with GzhInfoCNamed {
  self: PandoraMongodb with Logging ⇒

  import GzhInfo._
  import org.mongodb.scala.bson.codecs.Macros._
  import org.bson.codecs.configuration.CodecRegistry

  protected val codecRegistry: CodecRegistry = registries(classOf[H5], classOf[GzhInfo])

  protected val toBson: GzhInfo ⇒ MO = (info: GzhInfo) ⇒ {
    val GzhInfo(
      id,
      name,
      gzhid,
      appid,
      secret,
      token,
      qunku,
      channelId,
      isAlive,
      h5,
      createTime,
      updateTime
    ) = info
    MO(
      "_id"        → id,
      "name"       → name,
      "gzhid"      → gzhid,
      "appid"      → appid,
      "secret"     → secret,
      "token"      → token,
      "qunku"      → qunku,
      "channelId"  → channelId,
      "isAlive"    → isAlive,
      "createTime" → createTime,
      "updateTime" → updateTime
    ) ++ h5.map(h ⇒ MO("h5.qrCode" → h.qrCode, "h5.description" → h.description)).getOrElse(MO())
  }

  protected val _Collection: MongoCollection[GzhInfo] =
    _Mongodb.db.withCodecRegistry(codecRegistry).getCollection(tableName)
}

class GzhInfos(
    implicit
    val _Mongodb: MongodbContext,
    val ec: ExecutionContext
) extends GzhInfoCollection
    with PandoraMongodb
    with Logging {

  val appId: String ⇒ MO = id ⇒ MO("appid" → id)

  def findOne(id: String): Future[GzhInfo] = findOne(appId(id)).map {
    case Some(info) ⇒ info
    case None       ⇒ throw GzhInfo.NotFound(id)
  }

  def deleteOne(id: String): Future[Boolean] = deleteOne(appId(id))

  def updateOne(id: String, info: GzhInfo): Future[GzhInfo] =
    updateOne(appId(id), info)

  def remove(id: String): Future[Boolean] = deleteMany(appId(id))
}

trait GzhInfoCNamed extends CanonicalNamed {

  override val basicName: String = "gzhs"
}
